package com.tanhua.dubbo.server.api;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import com.alibaba.dubbo.config.annotation.Service;
import com.tanhua.common.pojo.RecommendUser;
import com.tanhua.dubbo.server.pojo.UserLike;
import org.bson.types.ObjectId;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * Created with IntelliJ IDEA.
 *
 * @ClassName: UserLikeApiImpl
 * @Author:王晨晗
 * @Description: 用户喜欢
 * @Date: 2022/01/07/9:04
 */
@Service
public class UserLikeApiImpl implements UserLikeApi{
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private RedisTemplate<String , String> redisTemplate;
    //用户喜欢的key前缀
    public static final String LIKE_REDIS_KEY_PREFIX = "USER_LIKE_";
    //用户不喜欢的key前缀
    public static final String NOT_LIKE_REDIS_KEY_PREFIX = "USER_NOT_LIKE_";

    /**
     * @description 喜欢
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean likeUser(Long userId, Long likeUserId) {
        //判断该用户是否已经喜欢 , 如果已经喜欢就直接返回
        if (isLike(userId , likeUserId)){
            return false;       //喜欢失败
        }
        //创建用户喜欢对象;
        UserLike userLike = new UserLike();
        //封装userlike对象
        userLike.setUserId(userId);             //用户id
        userLike.setId(ObjectId.get());         //主键id
        userLike.setLikeUserId(likeUserId);     //喜欢的用户id
        userLike.setCreated(System.currentTimeMillis());    //创建时间
        //将数据存储到mongodb
        mongoTemplate.save(userLike);
        //将用户喜欢存入redis
        String redisKey = LIKE_REDIS_KEY_PREFIX + userId;       //键值
        String hashKey = String.valueOf(likeUserId);            //字段
        //执行添加
        redisTemplate.opsForHash().put(redisKey , hashKey , "1");

        //判断,喜欢的用户是否在不喜欢的列表中,如果在就要删除数据
        if (isNotLike(userId , likeUserId)){
            //获取redis中不喜欢的字段名
            redisKey = NOT_LIKE_REDIS_KEY_PREFIX + userId;
            //执行删除
            redisTemplate.opsForHash().delete(redisKey , hashKey);
        }
        //返回喜欢成功结果;
        return true;
    }

    /**
     * @description 不喜欢
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean notLikeUser(Long userId, Long likeUserId) {
        //判断用户是否已经不喜欢，如果已经不喜欢，就返回
        if(isNotLike(userId, likeUserId)){
            return false;   //不喜欢失败;
        }
        //将用户保存到不喜欢列表中
        String redisKey = NOT_LIKE_REDIS_KEY_PREFIX + userId;
        //redis中不喜欢字段名;
        String hashKey = String.valueOf(likeUserId);
        //添加到不喜欢列表
        redisTemplate.opsForHash().put(redisKey, hashKey, "1");
        //判断用户是否在喜欢列表中，如果存在的话，需要删除数据
        if(isLike(userId, likeUserId)){
            //删除MongoDB数据
            Query query = Query.query(Criteria
                    .where("userId").is(userId)
                    .and("likeUserId").is(likeUserId));
            //执行删除
            mongoTemplate.remove(query, UserLike.class);
            //删除redis中喜欢的数据
            redisKey = LIKE_REDIS_KEY_PREFIX + userId;
            //执行删除命令
            redisTemplate.opsForHash().delete(redisKey, hashKey);
        }
        //返回不喜欢成功;
        return true;
    }

    /**
     * @description 是否相互喜欢
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public Boolean isMutualLike(Long userId, Long likeUserId) {
        //调用是否喜欢方法, 获取比较结果;
        return isLike(userId , likeUserId) && isLike(likeUserId , userId);
    }

    /**
     * @description 查询喜欢列表
     * @param userId
     * @return
     */
    @Override
    public List<Long> queryLikeList(Long userId) {
        //查询redis
        String redisKey = LIKE_REDIS_KEY_PREFIX + userId;
        //获取Redis中此键的所有字段
        Set<Object> keys = redisTemplate.opsForHash().keys(redisKey);
        //判断字段是否为空
        if (CollUtil.isEmpty(keys)){
            //返回空集合
            return ListUtil.empty();
        }
        //获取所有的字段进行转换
        List<Long> result = new ArrayList<>(keys.size());
        //将字符串类型转为long类型
        keys.forEach(o -> result.add(Convert.toLong(o)));
        //返回结果集
        return result;
    }

    /**
     * @description 查询不喜欢列表
     * @param userId
     * @return
     */
    @Override
    public List<Long> queryNotLikeList(Long userId) {
        //查询redis
        String redisKey = NOT_LIKE_REDIS_KEY_PREFIX + userId;
        //获取Redis中此键的所有字段
        Set<Object> keys = redisTemplate.opsForHash().keys(redisKey);
        //判断字段是否为空
        if (CollUtil.isEmpty(keys)){
            //返回空集合
            return ListUtil.empty();
        }
        //获取所有的字段进行转换
        List<Long> result = new ArrayList<>(keys.size());
        //将字符串类型转为long类型
        keys.forEach(o -> result.add(Convert.toLong(o)));
        //返回结果集
        return result;
    }

    /**
     * @description 查询相互喜欢数
     * @param userId
     * @return
     */
    @Override
    public Long queryEachLikeCount(Long userId) {
        //查询我的喜欢列表
        Query query = Query.query(Criteria.where("userId").is(userId));     //构建查询条件
        //执行查询,获取到用户喜欢对象集合;
        List<UserLike> userLikes = mongoTemplate.find(query, UserLike.class);
        //获取喜欢的id集合
        List<Object> likeUserIds = CollUtil.getFieldValues(userLikes, "likeUserId");

        //查询在我喜欢中,喜欢我的用户
        Query query1 = Query.query(Criteria.where("userId").in(likeUserIds).and("likeUserId").is(userId));
        //执行查询,获取数量;
        long count = mongoTemplate.count(query1, UserLike.class);
        //返回相互喜欢数
        return count;
    }

    /**
     * @description 查询喜欢数
     * @param userId
     * @return
     */
    @Override
    public Long queryLoveCount(Long userId) {
        //查询我喜欢的列表,返回我喜欢的人数
        return mongoTemplate.count(Query.query(Criteria.where("userId").is(userId)) , UserLike.class);
    }

    /**
     * @description 粉丝数
     * @param userId
     * @return
     */
    @Override
    public Long queryFanCount(Long userId) {
        //查询喜欢我的列表, 返回粉丝数量;
        return mongoTemplate.count(Query.query(Criteria.where("likeUserId").is(userId)) , UserLike.class);
    }

    /**
     * @description 相互喜欢列表
     * @param userId
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public List<RecommendUser> queryEachLikeList(Long userId, Integer page, Integer pageSize , String nickName) {
        //查询我的喜欢列表
        Query query = Query.query(Criteria.where("userId").is(userId));
        //执行查询,获取到用户喜欢列表;
        List<UserLike> userLikes = mongoTemplate.find(query, UserLike.class);
        //获取喜欢的id集合
        List<Object> likeUserIds = CollUtil.getFieldValues(userLikes, "likeUserId");

        //查询在我喜欢中,喜欢我的用户
        //分页条件
        PageRequest pageRequest = PageRequest.of(page -1 , pageSize);
        //构建查询条件
        Query query1 = new Query(Criteria.where("userId").in(likeUserIds).and("likeUserId").is(userId)).with(Sort.by(Sort.Order.desc("created")));
        //判断昵称是否为空,决定后续条件 , 是否分页;
        if (StrUtil.isEmpty(nickName)){
            query1.with(pageRequest);
        }
        //执行查询,获取相互喜欢的集合;
        List<UserLike> userLikes1 = mongoTemplate.find(query1, UserLike.class);
        //封装推荐用户集合
        List<RecommendUser> list = new ArrayList<>();
        //遍历用户相互喜欢集合
        for (UserLike userLike : userLikes1) {
            //根据喜欢的用户id ,查询对应用户的缘分值, 进行封装到推荐用户实体类中
            RecommendUser recommendUser = queryScore(userLike.getUserId(), userLike.getLikeUserId());
            //添加至集合;
            list.add(recommendUser);
        }
        //返回结果集
        return list;
    }

    /**
     * @description 喜欢列表
     * @param userId
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public List<RecommendUser> queryLoveList(Long userId, Integer page, Integer pageSize , String nickName) {
        //构建分页条件,按创建时间降序排列
        PageRequest pageRequest = PageRequest.of(page -1 , pageSize);
        //构建查询条件
        Query query = Query.query(Criteria.where("userId").is(userId)).with(Sort.by(Sort.Order.desc("created")));
        //判断是否模糊查询
        if (StrUtil.isEmpty(nickName)){
            query.with(pageRequest);
        }
        //执行查询,获取到用户喜欢集合
        List<UserLike> userLikes = mongoTemplate.find(query, UserLike.class);
        //封装推荐用户集合
        List<RecommendUser> list = new ArrayList<>();
        //遍历用户喜欢集合
        for (UserLike userLike : userLikes) {
            //查询喜欢用户的缘分值,获取到推荐用户对象
            RecommendUser recommendUser = queryScore(userLike.getLikeUserId(), userLike.getUserId());
            //添加至集合
            list.add(recommendUser);
        }
        //返回结果集合
        return list;
    }

    /**
     * @description 粉丝列表
     * @param userId
     * @param page
     * @param pageSize
     * @return
     */
    @Override
    public List<RecommendUser> queryFanList(Long userId, Integer page, Integer pageSize , String nickName) {
        //构建分页条件,按创建时间降序排列
        PageRequest pageRequest = PageRequest.of(page -1 , pageSize);
        //构建查询条件
        Query query = Query.query(Criteria.where("likeUserId").is(userId)).with(Sort.by(Sort.Order.desc("created")));
        //判断是否模糊查询
        if (StrUtil.isEmpty(nickName)){
            query.with(pageRequest);
        }
        //执行查询,获取到用户喜欢集合
        List<UserLike> userLikes = mongoTemplate.find(query, UserLike.class);
        //封装推荐用户集合
        List<RecommendUser> list = new ArrayList<>();
        //遍历用户粉丝集合
        for (UserLike userLike : userLikes) {
            //查询粉丝用户的缘分值,获取到推荐用户对象
            RecommendUser recommendUser = queryScore(userLike.getUserId(), userLike.getLikeUserId());
            //添加至集合
            list.add(recommendUser);
        }
        //返回结果集合
        return list;
    }

    /**
     * @description 判断用户是否喜欢了一个用户
     * @param userId
     * @param likeUserId
     * @return
     */
    @Override
    public boolean isLike(Long userId, Long likeUserId) {
        //Redis中键的名字
        String redisKey = LIKE_REDIS_KEY_PREFIX + userId;
        //对应键的字段的名字
        String hashKey = String.valueOf(likeUserId);
        //判断redis中是否有这个键,返回结果
        return redisTemplate.opsForHash().hasKey(redisKey , hashKey);
    }

    /**
     * @description 判断用户是否不喜欢一个用户
     * @param userId
     * @param likeUserId
     * @return
     */
    private boolean isNotLike(Long userId, Long likeUserId) {
        //Redis中键的名字
        String redisKey = NOT_LIKE_REDIS_KEY_PREFIX + userId;
        //对应键的字段的名字
        String hashKey = String.valueOf(likeUserId);
        //判断redis中是否有这个键,返回结果
        return redisTemplate.opsForHash().hasKey(redisKey , hashKey);
    }

    /**
     * @description  根据用户id 和推荐人id 查询推荐表的分值  是否存在推荐关系 ,封装结果
     * @param userId
     * @param toUserId
     * @return
     */
    public RecommendUser queryScore(long userId, long toUserId) {
        //构建查询条件
        Query query = Query.query(Criteria.where("userId").is(userId).and("toUserId").is(toUserId));
        //获取查询结果
        RecommendUser user = mongoTemplate.findOne(query, RecommendUser.class);
        //如果为空,注入默认匹配值
        if (user == null) {
            //创建推荐用户对象
            user = new RecommendUser();
            //封装数据
            user.setUserId(userId);         //用户id
            user.setToUserId(toUserId);     //喜欢用户id
            user.setScore(85d);             //缘分值
        }
        //不为空, 直接返回结果
        return user;
    }
}
